/*
 *  Copyright (C) 2010 Glauco
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.balisunrise.swing.transaction;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JPanel;
import org.balisunrise.annotation.ActionCancel;
import org.balisunrise.annotation.ActionConfirm;
import org.balisunrise.common.DAO;
import org.balisunrise.common.TransactionMode;
import org.balisunrise.common.events.TransactionModeChangedEvent;
import org.balisunrise.common.TransactionModeListener;
import org.balisunrise.common.VisualAction;
import org.balisunrise.common.VisualEntityType;
import org.balisunrise.common.abstracts.AbstractVisualEntity;
import org.balisunrise.common.defaults.DefaultTrasactionModeChangedEvent;
import org.balisunrise.common.events.VisualActionEvent;
import org.balisunrise.swing.transaction.panel.TransactionActionPanel;

/**
 *
 * @author Glauco
 */
public class TransactionActions extends AbstractVisualEntity
        implements org.balisunrise.common.TransactionActions
        <Transaction, VisualAction, JPanel>{

    private Transaction transaction;
    private Method createMethod;
    private List<VisualAction> actions;
    private int mode;
    private int oldMode;
    private TransactionActionPanel visualRepresentation;
    private List<TransactionModeListener> tmListener;

    public TransactionActions(){
        actions = new ArrayList<VisualAction>();
        tmListener = new ArrayList<TransactionModeListener>();
    }

    public void setVisualRepresentation(TransactionActionPanel visualRepresentation) {
        this.visualRepresentation = visualRepresentation;
    }

    public int getMode() {
        return mode;
    }

    public void setMode(int mode) {
        this.oldMode = this.mode;
        this.mode = mode;
        if(visualRepresentation != null)
            visualRepresentation.selectButton(mode);
    }

    public Transaction getTransaction() {
        return transaction;
    }

    public void setCreateMethod(Method createMethod){
        this.createMethod = createMethod;
    }

    public JPanel getVisualRepresentation() {
        return visualRepresentation;
    }

    public void setTransaction(Transaction transaction) {
        this.transaction = transaction;
    }

    public void addListener(TransactionModeListener listener) {
        tmListener.add(listener);
    }

    public void removeListener(int index) {
        if(tmListener.size() > index && index >= 0)
            tmListener.remove(index);
    }

    public void removeListener(TransactionModeListener listener) {
        try{
            tmListener.remove(listener);
        }catch(Exception ex){
            System.out.println(ex.getMessage());
        }
    }

    public TransactionModeListener[] getListeners() {
        return (TransactionModeListener[]) tmListener.toArray();
    }

    public void addAction(VisualAction action) {
        actions.add(action);
        if(visualRepresentation != null)
            visualRepresentation.addAction(
                    (JButton) action.getVisualRepresentation(),
                    getActions().length);
    }

    public void addAction(VisualAction action, int index) {

        if (index < 0 || action == null)
            return;

        if (index >= actions.size())
            actions.add(action);
        else
            actions.add(index, action);

        if (visualRepresentation != null)
            visualRepresentation.addAction(
                    (JButton) action.getVisualRepresentation(),
                    getActions().length);
    }

    public VisualAction[] getActions() {

        if (actions != null)
            return actions.toArray(new VisualAction[]{});

        return null;
    }

    public void doAction(int index) {

        if (index < 0 || index > actions.size())
            return;

        final VisualAction va = actions.get(index);
        va.perform(new VisualActionEvent() {

            public VisualAction getVisualAction() {
                return va;
            }
        });
    }

    @ActionConfirm(alias="", text="Confirmar", toolTipText="Confirmar")
    public void actionConfirm() {
        switch (mode) {
            case TransactionMode.SEARCH:
                confirmSearch();
                break;
            case TransactionMode.NEW:
                confirmNew();
                break;
            case TransactionMode.UPDATE:
                confirmEdit();
                break;
            case TransactionMode.DELETE:
                confirmDelete();
                break;
        }
    }

    @ActionCancel(alias = "", text = "Cancelar", toolTipText="Cancelar")
    public void actionCancel() {
        switch (mode) {
            case TransactionMode.SEARCH:
                cancelSearch();
                break;
            case TransactionMode.NEW:
                cancelNew();
                break;
            case TransactionMode.UPDATE:
                cancelEdit();
                break;
            case TransactionMode.DELETE:
                cancelDelete();
                break;
        }
    }

    public void doSearch() {
        if (mode == TransactionMode.SEARCH) {

            // mostra a busca
            getTransaction().showSearch();

            // Ativa eventos dos listners
            fireTransactionModeChanged();

        }
    }

    public void doNew() {
        if (mode == TransactionMode.SEARCH) {
            setMode(TransactionMode.NEW);
            getTransaction().showEditor();
            getTransaction().getEditor().setEntity(newEntity());
            
            org.balisunrise.common.EntityPanel<JPanel> entityPanel =
                    getTransaction().getEditor().getEntityPanel();

            entityPanel.getVisualRepresentation().setEnabled(true);
            
            // Ativa eventos dos listners
            fireTransactionModeChanged();
        }
    }

    public void doEdit() {
        if (mode == TransactionMode.SEARCH &&
                getTransaction().getSearch().getSelectedEntity() != null) {
            setMode(TransactionMode.UPDATE);
            getTransaction().showEditor();
            getTransaction().getEditor().setEntity(
                    getTransaction().getSearch().getSelectedEntity());

            org.balisunrise.common.EntityPanel<JPanel> entityPanel =
                    getTransaction().getEditor().getEntityPanel();

            entityPanel.getVisualRepresentation().setEnabled(true);

            // Ativa eventos dos listners
            fireTransactionModeChanged();
        }
    }

    public void doDelete() {
        if (mode == TransactionMode.SEARCH &&
                getTransaction().getSearch().getSelectedEntity() != null) {
            setMode(TransactionMode.DELETE);

            getTransaction().showEditor();
            
            org.balisunrise.common.Editor<?,?,?,JPanel> editor = 
                    getTransaction().getEditor();

            editor.setEntity(getTransaction().getSearch().getSelectedEntity());
            
            org.balisunrise.common.EntityPanel<JPanel> entityPanel = 
                    editor.getEntityPanel();

            entityPanel.getVisualRepresentation().setEnabled(false);

            // Ativa eventos dos listners
            fireTransactionModeChanged();
        }
    }

    private void confirmSearch() {
        doEdit();
    }

    private void confirmNew() {
        if (getTransaction().getEditor().getEntityPanel().isEntityValid() &&
                !getTransaction().getEditor().getMessenger().hasError()) {
            DAO dao = getDAO();
            dao.save(getTransaction().getEditor().getEntity());
            setMode(TransactionMode.SEARCH);
            doSearch();
        }
    }

    private void confirmEdit() {
        if (getTransaction().getEditor().getEntityPanel().isEntityValid() &&
                !getTransaction().getEditor().getMessenger().hasError()) {
            DAO dao = getDAO();
            dao.save(getTransaction().getEditor().getEntity());
            setMode(TransactionMode.SEARCH);
            doSearch();
        }
    }

    private void confirmDelete() {
        DAO dao = getDAO();
        dao.delete(getTransaction().getEditor().getEntity());
        setMode(TransactionMode.SEARCH);
        doSearch();
    }

    private void cancelSearch() {
        getTransaction().getSearch().newSearch();
    }

    private void cancelNew() {
        setMode(TransactionMode.SEARCH);
        doSearch();
    }

    private void cancelEdit() {
        setMode(TransactionMode.SEARCH);
        doSearch();
    }

    private void cancelDelete() {
        setMode(TransactionMode.SEARCH);
        doSearch();
    }

    private Serializable newEntity() {

        if (createMethod != null)
            try{
                Object o = createMethod.invoke(null);
                if (getEntityClass().isInstance(o))
                    return (Serializable) o;
            }catch(Exception ex){
                System.out.println(ex.getMessage());
            }

        try {
            return (Serializable) getTransaction().getEntityClass().newInstance();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return null;
    }

    private void fireTransactionModeChanged(){

        if (tmListener.isEmpty())
            return ;
        
        TransactionModeChangedEvent evt =
                new DefaultTrasactionModeChangedEvent(
                    getTransaction(),
                    oldMode,
                    mode);

        for (TransactionModeListener tml : tmListener) {
            tml.transactionModeChanged(evt);
        }
    }

    /**
     * Retorna o tipo do VisualEntity.<BR>
     * Sempre retornará TRANSACTION_ACTIONS.
     * @return VisualEntityType.TRANSACTION_ACTIONS
     */
    public VisualEntityType getVisualEntityType() {
        return VisualEntityType.TRANSACTION_ACTIONS;
    }
}
